package proxy

import (
	"time"

	log "github.com/sirupsen/logrus"
	"github.com/valyala/fasthttp"
)

type fasthttpForwarding struct {
	client *fasthttp.Client
	timeout int
}

func newFasthttpForwarding() *fasthttpForwarding {
	return &fasthttpForwarding{
		client: &fasthttp.Client{
			Name: "proxy-client",
			ReadTimeout: 30 * time.Second,
		},
		timeout: 30,
	}
}

func (f *fasthttpForwarding) Forwarding() error {
	go f.doForwarding()
	return nil 
}

func (f *fasthttpForwarding) doForwarding() {
	err := fasthttp.ListenAndServe("0.0.0.0:80", f.handler)
	if err != nil {
		log.Fatal("fast http server start error")
	}
}

func (f *fasthttpForwarding) DoStop() error {
	return nil
}

func (f *fasthttpForwarding) handler(c *fasthttp.RequestCtx) {
	serviceName := getServiceName2(c)
	if serviceName == "" {
		errResp(c, 500, "cannot find service")
		return 
	}
	serviceGroup := getServiceGroup2(c)

	ip, port, err := choose(serviceName, serviceGroup)
	if err != nil {
		errResp(c, 500, err.Error())
		return 
	}

	newuri := reconstructuri(string(c.Request.Header.RequestURI()), ip, port)

	nreq := fasthttp.AcquireRequest()
	defer fasthttp.ReleaseRequest(nreq)

	c.Request.CopyTo(nreq)
	nreq.SetHost("")
	nreq.SetRequestURI(newuri)

	nresp := fasthttp.AcquireResponse()
	defer fasthttp.ReleaseResponse(nresp)

	err = f.client.DoTimeout(nreq, nresp, time.Duration(f.timeout) * time.Second)
	if err != nil {
		errResp(c, 500, err.Error())
	}

	nresp.CopyTo(&c.Response)
}

func getServiceName2(c *fasthttp.RequestCtx) string {
	return string(c.Request.Header.Host())
}

func getServiceGroup2(c *fasthttp.RequestCtx) string {
	if groupHeader := c.Request.Header.Peek(ServiceGroupKey); groupHeader != nil {
		return string(groupHeader)
	}
	if cookieGroup := c.Request.Header.Cookie(ServiceGroupKey); cookieGroup != nil {
		return string(cookieGroup)
	}
	return ""
}

func errResp(c *fasthttp.RequestCtx, code int, msg string) {
	c.Response.SetStatusCode(code)
	c.Response.SetBodyString(msg)
}
